package com.smh.demo1.a41;

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;

import java.util.Optional;

/**
 * @author shiminghui
 * @date 2025/5/10 13:02
 * @description: TODO
 */
@Configuration
public class A41 {
    public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException {

        // 创建一个Spring应用上下文
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A41.class);
        //
        DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();

        //  1. 根据字段获取bean
        DependencyDescriptor dd1 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean2"), false);
        Object o = beanFactory.doResolveDependency(dd1, "bean1", null, null);
        System.out.println(o);
        System.out.println("----------------------------------------");
        // 2. 根据方法参数
        DependencyDescriptor dd2 = new DependencyDescriptor(new MethodParameter(Bean1.class.getMethod("setBean2", Bean2.class), 0), false);
        Object o1 = beanFactory.doResolveDependency(dd2, "bean1", null, null);
        System.out.println(o1);
        System.out.println("----------------------------------------");

        // 3. 解析泛型
        DependencyDescriptor dd3 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean2Optional"), false);
        System.out.println(dd3.getDependencyType());
        if (dd3.getDependencyType() == Optional.class) {
            dd3.increaseNestingLevel(); // 嵌套层级加1
            System.out.println(dd3.getDependencyType());
            Object o2 = beanFactory.doResolveDependency(dd3, "bean1", null, null);
            // 封装成Optional
            Optional<Object> o3 = Optional.ofNullable(o2);
            System.out.println(o3);
        }
        System.out.println("----------------------------------------");

        // 4. ObjectFactory
        DependencyDescriptor dd4 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean2ObjectFactory"), false);
        System.out.println(dd4.getDependencyType());
        if (dd4.getDependencyType() == ObjectFactory.class) {
            dd4.increaseNestingLevel();
            System.out.println(dd4.getDependencyType());
            ObjectFactory<Bean2> objectFactory = new ObjectFactory<>() {
                @Override
                public Bean2 getObject() {
                    return (Bean2) beanFactory.doResolveDependency(dd4, "bean1", null, null);
                }
            };
            System.out.println(objectFactory);
        }
        System.out.println("----------------------------------------");

        // 处理Lazy
        DependencyDescriptor dd5 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean2"), false);

        ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();
        resolver.setBeanFactory(beanFactory);
        Object bean2 = resolver.getLazyResolutionProxyIfNecessary(dd5, "bean1");
        System.out.println(bean2);
        System.out.println(bean2.getClass());


    }

    @Component
    static class Bean1 {
        @Autowired
        @Lazy
        private Bean2 bean2;
        @Autowired
        private Optional<Bean2> bean2Optional;
        @Autowired
        private ObjectFactory<Bean2> bean2ObjectFactory;

        @Autowired
        public void setBean2(Bean2 bean2) {
            this.bean2 = bean2;
        }

        @Override
        public String toString() {
            return super.toString();
        }

    }

    @Component
    static class Bean2 {
    }

}
